use crate::thread_pool::ThreadPoolManager;
use crate::{config_model::AppConfig, upload_helper};
use anyhow::Result;
use common_service::directory_guard::DirCleaner;
use common_service::{ffmpeg_helper, url_helper};
use log::{error, info, warn};
use remote_service::GWebRemoteService;
use remote_service::model::dto::TaskDTO;
use std::path::PathBuf;
use std::{env, fs, path::Path};
use url::Url;
use urlencoding::decode;

pub async fn execute_business_logic(thread: &ThreadPoolManager) -> Result<()> {
    let thread_name = std::thread::current()
        .name()
        .unwrap_or("unnamed")
        .to_string();
    let task: Option<TaskDTO>;
    let remote_service = &thread.remote_service;
    let site_info = &thread.site_info;
    let app_config = &thread.config;
    {
        let _guard = thread.startup_lock.lock().await; // 保证一次只启动一个线程
        info!(
            "任务线程 {},开始处理业务逻辑，并获取任务上锁...",
            thread_name
        );
        task = get_task(remote_service, site_info.site_id).await?;
        info!("任务线程 {}任务锁释放...", thread_name);
    };
    let mut task = match task {
        Some(t) => t,
        None => {
            warn!("线程{},未获取到任务！！！结束！！！！", thread_name);
            return Ok(());
        }
    };

    if !validate_task(&task) {
        return Ok(());
    }
    task.site_id = site_info.site_id;

    let local_work_directory = prepare_local_directory(&task, app_config)?;
    info!("生成的本地工作目录{:?}", local_work_directory);

    //创建一个目录守卫，出了作用域自动执行drop清理工作
    let _dir_guard = DirCleaner(local_work_directory.clone());

    let relative_file = url_helper::calculate_relative_path(
        &Url::parse(task.url.as_ref().unwrap())?,
        &Url::parse(&remote_service.config.url.video_visit_url_prefix)?,
    )
    .replace("/", "\\");
    let file_name = Path::new(&relative_file).file_name().unwrap();
    let local_temp_file = local_work_directory.join(file_name);
    let source_file =
        Path::new(&remote_service.config.target.host).join(decode(&relative_file)?.into_owned());
    copy_source_to_temp(source_file, local_temp_file)?;

    let index_file = local_work_directory.join("index.m3u8");
    let local_temp_file = local_work_directory.join(file_name);

    //耗时操作使用异步
    let if_success = ffmpeg_helper::mp4_to_m3u8(
        &app_config.ffmpeg_param.filename,
        local_temp_file.to_str().unwrap(),
        index_file.to_str().unwrap(),
        app_config.ffmpeg_param.segment_time,
        app_config.ffmpeg_param.thread_count,
    )
    .await;

    if !if_success {
        warn!("视频转换失败，任务结束");
        return Ok(());
    }
    upload_task_result(&local_work_directory, &task, &remote_service).await?;
    info!("任务线程 {} 业务逻辑处理完成", thread_name);
    Ok(())
}

/// 获取任务
async fn get_task(remote_service: &GWebRemoteService, site_id: i32) -> Result<Option<TaskDTO>> {
    match remote_service.get_task(site_id).await {
        Ok(task) => Ok(task),
        Err(e) => {
            error!("获取任务异常: {:?}", e);
            Ok(None)
        }
    }
}

/// 校验任务合法性
fn validate_task(task: &TaskDTO) -> bool {
    if task.url.is_none() || task.chapter_id <= 0 {
        error!("任务数据异常: {:?}", task);
        false
    } else {
        true
    }
}

/// 创建本地工作目录
fn prepare_local_directory(task: &TaskDTO, app_config: &AppConfig) -> Result<PathBuf> {
    let unique_string = url_helper::get_md5_string_result(task.url.as_ref().unwrap(), 10)?;
    let local_work_directory = Path::new(&app_config.task.temp_directory).join(unique_string);
    if !local_work_directory.exists() {
        fs::create_dir_all(&local_work_directory)?;
    }
    Ok(local_work_directory)
}

/// 拷贝源文件到临时目录
fn copy_source_to_temp(source: PathBuf, target: PathBuf) -> Result<()> {
    if target.exists() {
        fs::remove_file(&target)?;
    }
    info!("准备拷贝: {:?} -> {:?}", source, target);
    fs::copy(&source, &target)?;
    info!("拷贝完成: {:?} -> {:?}", source, target);
    Ok(())
}

/// 上传任务结果
async fn upload_task_result(
    local_work_directory: &Path,
    task: &TaskDTO,
    remote_service: &GWebRemoteService,
) -> Result<()> {
    let env = env::var("APP_ENV").unwrap_or_else(|_| "dev".to_string());
    let mut unique_directory = format!("{}\\{}\\{}", task.site_id, task.book_id, task.chapter_id);
    if env == "dev" {
        unique_directory = format!("dev\\{}", unique_directory);
    }
    warn!("当前环境{},上传目录为{}", env, unique_directory);
    let (has_error, path) = upload_helper::upload_directory_files(
        local_work_directory.to_str().unwrap(),
        &unique_directory,
    )
    .await;

    if has_error {
        error!("上传报错: {:?}", path);
        remote_service
            .upload_video_slice_result(task.site_id, task.chapter_id, "", -1, Some(&path))
            .await?;
    } else if path.is_empty() {
        error!("上传成功但返回路径为空");
        remote_service
            .upload_video_slice_result(task.site_id, task.chapter_id, "", -1, Some("返回路径为空"))
            .await?;
    } else {
        info!("上传成功,开始上报结果, path={}", path);
        if let Err(e) = remote_service
            .upload_video_slice_result(task.site_id, task.chapter_id, &path, 2, Some(""))
            .await
        {
            error!("上报请求结果异常: {:?}", e);
            return Err(e.into());
        } else {
            info!("上报请求结果成功，路径: {}", path);
        }
    }

    Ok(())
}
